/**
 * 
 */
package org.vsg.stock.basic.service.volchara;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vsg.stock.basic.domain.VolCharacterKlineDaily;
import org.vsg.stock.basic.domain.VolCharacterKlineDailyPK;
import org.vsg.stock.basic.domain.VolCharacterOfFigurePrepared;
import org.vsg.stock.basic.domain.VolFigureKlineDaily;
import org.vsg.stock.basic.persistence.VolFigureKlineDailyDao;
import org.vsg.stock.basic.service.handler.VolCharacterKlineDailyProcessor;
import org.vsg.stock.core.domain.StockDailyKLine;

/**
 * @author Bill Vison
 *
 */
public class DefaultSampleVolCharacterKlineDailyProcessor implements VolCharacterKlineDailyProcessor {

	private static final Logger logger = LoggerFactory.getLogger(DefaultSampleVolCharacterKlineDailyProcessor.class);	

	
	static private DateFormat df = new SimpleDateFormat("yyyy-MM-dd");	
	
	private Set<String> existKeys = new HashSet<String>();
	
	@Resource
	private VolFigureKlineDailyDao volFigureKlineDailyDao;	
	
	/**
	 * show list object
	 */
	private List<VolFigureKlineDaily> figureKLineDailyVec;
	
	@Override
	public List<VolCharacterKlineDaily> processDailyData(
			List<StockDailyKLine> stkDailyKLineList , String stockCode) {
		
		// ---- get the object ---
		figureKLineDailyVec = volFigureKlineDailyDao.findVolFiguKlineDailyByCharacterPrepared(stockCode);

		List<VolCharacterKlineDaily> volCharaKLineDailyVec = new Vector<VolCharacterKlineDaily>();
		
		List<Date> dateIndexVec = new Vector<Date>();
		for (StockDailyKLine kline : stkDailyKLineList) {
			dateIndexVec.add( kline.getDate() );
		}
		
		// ---- list stock daily kline ----
		StockDailyKLine stkLine = null;

		short lastState = -1;
		boolean recordData = false;
		for (int i = 0 ; i < stkDailyKLineList.size() ; i++) {
			
			int maxSize = i + 3;
			if ( maxSize >= stkDailyKLineList.size() ) {
				break;
			}
			
			stkLine = stkDailyKLineList.get(i);
			
			
			if (df.format( stkLine.getDate() ).equals("2009-01-16")) {
				System.out.println("log in");
			}
			
			// --- check state ----
			VolFigureKlineDaily entity = meetVolFigureKline( stkLine.getDate() );

			short currentState = analysisState(stkDailyKLineList , i , entity);
			String keyg =  stkLine.getId().getStockCode()+","+ df.format( stkLine.getDate()) + " , " + currentState;				

			if ( currentState > -1 ) {


				// --- 同样的记录先者优先 ---
				if (currentState != VolCharacterKlineDaily.UPGRADE_CLOSE_GOLDEN && currentState != VolCharacterKlineDaily.UPGRADE_TO_GOLDEN  ) {
					if (entity != null) {
						recordData = currentState != lastState ? true : false;
					} else {
						recordData = false;
					}
				} else {
					recordData = true;
				}
				
				//String key =  stkLine.getId().getStockCode()+","+ df.format( stkLine.getDate()) + " , " + currentState;				
				//System.out.println(key + " , " + entity);
			}

			// --- ---
		
			// --- mark record ---
			if (recordData) {
		
				// --- check the key exist ---
				String key =  stkLine.getId().getStockCode()+","+ df.format( stkLine.getDate());
				// --- 原先不存在 ---
				if ( !existKeys.contains(key) ) {
					
					VolCharacterKlineDaily characterDaily = new VolCharacterKlineDaily();
					characterDaily.setGoldenDate( stkLine.getDate() );
					characterDaily.setLevelGolden( currentState );
					
					VolCharacterKlineDailyPK pk = new VolCharacterKlineDailyPK();
					
					if (entity != null ) {
						pk.setStockCode( entity.getId().getStockCode() );
						pk.setStockStartDate( entity.getId().getStockStartDate() );
						characterDaily.setStockEndDate( entity.getStockDateEnd() );
					} else {
						pk.setStockCode( stockCode );
						pk.setStockStartDate( stkLine.getDate() );
						characterDaily.setStockEndDate( stkLine.getDate() );						
					}
					characterDaily.setId( pk );
					volCharaKLineDailyVec.add( characterDaily );
					
					existKeys.add( key );
				}

			}
			
			recordData = false;			
			lastState = currentState;
		}
		
		// ---- 寻找 梯量柱和平量柱的黄金柱 ---
		VolCharacterOfFigurePrepared charaOfFigurePrep = null;
		for (VolFigureKlineDaily entity : figureKLineDailyVec) {
			charaOfFigurePrep = entity.getCharacterPrepared();
			int index = 0;
			// --- 平量柱 ---
			if (charaOfFigurePrep.getVolFigureDetailsCode().startsWith("unbiased")) {
				// ---- 分析事后的缩量柱是否符合 将军柱 黄金柱的缩量特点 ----
				//if (df.format( entity.getId().getStockStartDate() ).equals("2009-04-28")) {
					//System.out.println("log in");
				//}				
				index = dateIndexVec.indexOf( entity.getId().getStockStartDate() ) + charaOfFigurePrep.getStartIndex();
			}
			// --- 增量柱 ----
			else if (charaOfFigurePrep.getVolFigureDetailsCode().startsWith("increase")) {
				//System.out.println(charaOfFigurePrep.getVolFigureDetailsCode());
			}
			if (index >= stkDailyKLineList.size() ) {
				break;
			}
			short currentState = analysisState(stkDailyKLineList , index , entity);
			
			// --- add object ---
			Date indexDate = dateIndexVec.get(index);
			// --- check the key exist ---
			String key =  entity.getId().getStockCode()+","+ df.format( indexDate );
			// --- 原先不存在 ---
			if ( !existKeys.contains(key) &&  currentState > -1) {
				
				VolCharacterKlineDaily characterDaily = new VolCharacterKlineDaily();
				characterDaily.setGoldenDate( indexDate );
				characterDaily.setLevelGolden( currentState );
				
				VolCharacterKlineDailyPK pk = new VolCharacterKlineDailyPK();
				pk.setStockCode( entity.getId().getStockCode() );
				pk.setStockStartDate( entity.getId().getStockStartDate() );
				characterDaily.setStockEndDate( entity.getStockDateEnd() );

				characterDaily.setId( pk );
				
				existKeys.add( key );
			}			
		}
		
		// ---- filter and arrange ----
		Collections.sort(volCharaKLineDailyVec, new CharaKLineDailySortComparator() );
		
		if (this.logger.isDebugEnabled()) {
			
			VolCharacterKlineDaily volCharaKlineDaily = null;
			for (Iterator<VolCharacterKlineDaily> dailVecIter = volCharaKLineDailyVec.iterator() ; dailVecIter.hasNext();) {
				volCharaKlineDaily = dailVecIter.next();
				
			}
			for ( VolCharacterKlineDaily entity : volCharaKLineDailyVec) {
				String key =  entity.getId().getStockCode()+","+ df.format( entity.getGoldenDate() ) + " , " + entity.getLevelGolden() +" , " +  df.format( entity.getId().getStockStartDate() );			
				System.out.println(key);
			}
			
		}

		
		
		
		
		return volCharaKLineDailyVec;
	}

	@Override
	public void setExistedVolCharacterKlineDaily(
			List<VolCharacterKlineDaily> existedList) {
		for (VolCharacterKlineDaily exitsDaily : existedList) {
			String line = exitsDaily.getId().getStockCode()+","
				+ df.format( exitsDaily.getGoldenDate() ) ;
			existKeys.add(line);
		}
		
	}
	
	private VolFigureKlineDaily meetVolFigureKline(Date charaDate) {
		
		VolFigureKlineDaily result = null;

		for (VolFigureKlineDaily entity : figureKLineDailyVec) {
			
			if ( !entity.getId().getStockStartDate().after( charaDate ) && 
					!entity.getStockDateEnd().before( charaDate ) )	{
				result = entity;
				break;
			}
		}
		return result;
	}

	private short analysisState(List<StockDailyKLine> stkDailyKLineList , int index , VolFigureKlineDaily entity) {
		
		short state = -1;
		
		boolean result = isGeneralVol(stkDailyKLineList , index);
		
		// ---不符合将军柱 ---
		if ( !result ) {
			// --- 分析缺口柱 ----
			result = isUpgradeGoldenVol(stkDailyKLineList , index);
			if ( result ) {
				state = VolCharacterKlineDaily.UPGRADE_CLOSE_GOLDEN;
			}
			return state;
			
		}
		state = VolCharacterKlineDaily.GENERAL;
		
		result = isGoldenVol(stkDailyKLineList , index);
		if ( result) {
			state = VolCharacterKlineDaily.GOLDEN;
			return state;
		}
		
		// --- check fit the second golden rules
		if ( index + 3 < stkDailyKLineList.size() ) {
			boolean res = false;
			for (int i = 1; i < 4 ;i++ ) {
				int startIndex = index + i;
				if ( !res ) {
					res = isUpgradeRealGoldenVol(stkDailyKLineList , startIndex);
					break;
				}
			}
			// --- 必须是四类量柱之一 ----
			if ( res && entity != null) {
				result = res;
				state = VolCharacterKlineDaily.UPGRADE_TO_GOLDEN;
				return state;
			}
		}
		
		// --- 缺口前升为黄金柱 ---
		boolean breachExist = isUpgradeGoldenVol(stkDailyKLineList , index);
		if ( breachExist ) {
			state = VolCharacterKlineDaily.UPGRADE_CLOSE_GOLDEN;
			return state;
		}
		
		result = isSecondaryGolden(stkDailyKLineList , index);
		if ( result) {
			state = VolCharacterKlineDaily.SECONDARY_GOLDEN;
			return state;
		}
		
		
		return state;
	}
	
	/**
	 * 将军柱算法
	 * @param stkDailyKLineList
	 * @param index
	 * @return
	 */
	private boolean isGeneralVol(List<StockDailyKLine> stkDailyKLineList , int index) {
		
		StockDailyKLine comparedKLine = stkDailyKLineList.get( index );

		//double lowPrice = comparedKLine.getLow();
		double virOpenPrice = comparedKLine.getOpen() > comparedKLine.getClose() ? comparedKLine.getClose() : comparedKLine.getOpen();
		double virLowestPrice = comparedKLine.getLow();

		VolFigureKlineDaily entity = meetVolFigureKline( comparedKLine.getDate() );
		
		// --- 检查是否高开低走的假阴柱 ---
		boolean notFalse = false;
		if ( comparedKLine.getYieldRate() >= 0 && comparedKLine.getOpen() > comparedKLine.getClose() ) {
			notFalse = true;
		}
		
		// ---  case 1 ----
		// --- after compared date
		StockDailyKLine tmpKLine = null;
		int startIndex = 0;
		
		boolean result = false;
		//long sumVol = 0;

		for (int i = 1 ; i < 4 ; i++) {
			startIndex = index + i;
			tmpKLine = stkDailyKLineList.get( startIndex );
			
			
			// --- not beneath the lowest price ---
			if ( tmpKLine.getClose() < virLowestPrice ) {
				break;
			}
			
			if (i == 3) {
				
				if (tmpKLine.getClose() - tmpKLine.getOpen() > 0) {
					result = tmpKLine.getClose() > virOpenPrice;
				} else {
					result = tmpKLine.getClose() > virLowestPrice;
				}
			}

		}
		
		result = result && entity != null;
		
		// --- case 2 --- 价升量缩

		
		return result;
	}
	
	
	/**
	 * 黄金柱算法
	 * @param stkDailyKLineList
	 * @param index
	 * @return
	 */
	private boolean isGoldenVol(List<StockDailyKLine> stkDailyKLineList , int index) {
		StockDailyKLine comparedKLine = stkDailyKLineList.get( index );
		long comparedVol = comparedKLine.getVol();
		
		double closePrice = comparedKLine.getClose();
		// --- after compared date
		StockDailyKLine tmpKLine = null;
		int startIndex = 0;
	
		boolean result = true;
		long lastVol = comparedVol;
		
		// --- case 1 --- 标准黄金柱
		for (int i = 1 ; i < 4 ; i++) {
			startIndex = index + i;
			tmpKLine = stkDailyKLineList.get( startIndex );

			
			// 当前的量 大于 前一天的量就退出, decrease step by step
			if ( i > 1 && lastVol < tmpKLine.getVol()) {
				result = false;
				break;
			}
			
			double diffPrice = tmpKLine.getClose() - tmpKLine.getOpen();

			if (! (diffPrice > 0 || tmpKLine.getYieldRate() >= 0) ) {
				result = false;
				break;
			}
			
			// the third vol not greater than  the compared vol 
			if ( i == 3) {
				if (tmpKLine.getVol() < comparedVol && tmpKLine.getClose() >= closePrice ) {
					result = true;
				}
			}
			
			lastVol = tmpKLine.getVol();
		}
		
		// ---- case 2 --- 非标准黄金柱定义 
		
		return result;
	}
	
	
	/**
	 * 次黄金柱算法
	 * @param stkDailyKLineList
	 * @param index
	 * @return
	 */
	private boolean isSecondaryGolden(List<StockDailyKLine> stkDailyKLineList , int index) {
		StockDailyKLine comparedKLine = stkDailyKLineList.get( index );
		long comparedVol = comparedKLine.getVol();
		double closePrice = comparedKLine.getClose();
	

		// --- after compared date

		boolean result = true;
		
		int countUnderYield = 0;

		// --- after compared date
		StockDailyKLine tmpKLine = null;
		int startIndex = 0;		
		


		int countOverComparedVol = 0;
		long lastVol = 0;
		// --- 是否量柱步步低 ---
		boolean decreaseStepByStep = true;		
		// --- 是否第三天高于收盘价 ---
		boolean overClose = false;
		
		// --- 无跌破开盘价 ---
		boolean breakOpen = false; 
		
		for (int i = 1 ; i < 4 ; i++) {
			startIndex = index + i;
			tmpKLine = stkDailyKLineList.get( startIndex );
			
			// --- 计算不超过 2条阴线或下跌,假阳柱不算 ---
			boolean upPrice = tmpKLine.getYieldRate() > 0 || (tmpKLine.getClose() - tmpKLine.getOpen()) > 0;
			if ( upPrice) {
				countUnderYield++;
			}
			double lowButtonPrice = comparedKLine.getClose() < comparedKLine.getOpen() ? comparedKLine.getClose() : comparedKLine.getOpen();
			if ( lowButtonPrice > tmpKLine.getClose()) {
				breakOpen = true;
			}


			if ( i == 3) {
				if (tmpKLine.getClose() >= closePrice ) {
					overClose = true;
				}
			}
			
			// --- 量的处理 ---
			if (tmpKLine.getVol() > comparedVol) {
				countOverComparedVol++;
			}
			// 当前的量 大于 前一天的量就退出
			if (i > 1) {
				if (decreaseStepByStep && lastVol < tmpKLine.getVol()) {
					decreaseStepByStep = false;
				}			
			}

			lastVol = tmpKLine.getVol();
		}
		
		// --- 量柱不能超过 ---
		boolean notOverVolCount = true;
		if ( countOverComparedVol > 1) {
			notOverVolCount = false;
		}
		
		
		// --- 以是否高于收盘价分析 ---
		boolean countUpPrice = countUnderYield > 1; 
		/*
		if (overClose) {
			
			
		} else {
			result = notOverVolCount &&  countUpPrice || decreaseStepByStep;
		}
		*/
		result = notOverVolCount &&  countUpPrice && !breakOpen;

		//result = notOverVolCount && (overClose || decreaseStepByStep )&& countUnderYield < 2;
		
		return result;
	}

	private boolean isUpgradeGoldenVol(List<StockDailyKLine> stkDailyKLineList , int index ) {
		int nextIndex = index + 1;
		StockDailyKLine currnetKLine = stkDailyKLineList.get( index );
		StockDailyKLine nextKLine = stkDailyKLineList.get( nextIndex );
		
		if ( nextIndex + 3 >= stkDailyKLineList.size() ) {
			return false;
		}
		
		// --- 不能 < 0
		if ( currnetKLine.getYieldRate() < 0) {
			return false;
		}
	
	
		// --- 是否跳高开 ---
		boolean  breachExist = false;
		if ( currnetKLine.getYieldRate() >= 0 && nextKLine.getYieldRate() >= 0) {
			breachExist = currnetKLine.getClose() < nextKLine.getOpen();
		} else if ( currnetKLine.getYieldRate() <= 0 && nextKLine.getYieldRate() <= 0 ) {
			breachExist = currnetKLine.getClose() > nextKLine.getOpen();
		}
		/*
		if ( !breachExist ) {
			return false;
		}
		*/
		boolean isGeneralVol = isGeneralVol(stkDailyKLineList , nextIndex);
		boolean isGoldenVol = false;
		boolean isSecondaryGolden = false;
		if (isGeneralVol) {
			isGoldenVol = isGoldenVol(stkDailyKLineList , nextIndex);
			isSecondaryGolden = isSecondaryGolden(stkDailyKLineList , nextIndex);
		}
		
		boolean result = breachExist && (isGeneralVol || isSecondaryGolden || isGoldenVol); 

		return result;
	}
	
	private boolean isUpgradeRealGoldenVol(List<StockDailyKLine> stkDailyKLineList , int index) {
		int nextIndex = index + 1;
		StockDailyKLine currnetKLine = stkDailyKLineList.get( index );
		StockDailyKLine nextKLine = stkDailyKLineList.get( nextIndex );
		
		if ( nextIndex + 3 >= stkDailyKLineList.size() ) {
			return false;
		}
		
		// --- 不能 < 0
		if ( currnetKLine.getYieldRate() < 0) {
			return false;
		}
	
	
		// --- 是否跳高开 ---
		boolean  breachExist = false;
		if ( currnetKLine.getYieldRate() >= 0 && nextKLine.getYieldRate() >= 0) {
			breachExist = currnetKLine.getClose() < nextKLine.getOpen();
		} else if ( currnetKLine.getYieldRate() <= 0 && nextKLine.getYieldRate() <= 0 ) {
			breachExist = currnetKLine.getClose() > nextKLine.getOpen();
		}
		
		if ( !breachExist ) {
			return false;
		}
		boolean isGeneralVol = isGeneralVol(stkDailyKLineList , nextIndex);
		boolean isGoldenVol = isGoldenVol(stkDailyKLineList , nextIndex);
		boolean isSecondaryGolden = isSecondaryGolden(stkDailyKLineList , nextIndex);
		
		
		boolean result = breachExist && isGeneralVol && ( isSecondaryGolden || isGoldenVol); 

		return result;
	}
	
	private class CharaKLineDailySortComparator implements Comparator<VolCharacterKlineDaily> {

		@Override
		public int compare(VolCharacterKlineDaily arg0, VolCharacterKlineDaily arg1) {
			//VolCharacterKlineDaily first = (VolCharacterKlineDaily)arg0;
			//VolCharacterKlineDaily second = (VolCharacterKlineDaily)arg1;			
			int comp = arg0.getGoldenDate().compareTo(arg1.getGoldenDate());
			
			
			return comp;
		}
		
	}
}
